#ifndef __SSL__SSBASEL__SSTRACE__TRACE__H__
#define __SSL__SSBASEL__SSTRACE__TRACE__H__


#include "ssbase/base_export.h"

#ifdef FORCELIB
#define SSTRACE_API
#define SSTRACE_CLASS
#else
#ifdef SSTRACE_EXPORTS
#define SSTRACE_API _declspec(dllexport)
#define SSTRACE_CLASS _declspec(dllexport)
#else
#define SSTRACE_API _declspec(dllimport)
#define SSTRACE_CLASS _declspec(dllimport)
#endif
#endif

_SSL_BEGIN
_SSBASEL_BEGIN

//
#define TRACE_LEVEL_MASK                    0x000000FF
#define TRACE_LEVEL_DBG_DETAIL_MASK         0xFF000000
#define TRACE_LEVEL_ONLY(L)                 (L & TRACE_LEVEL_MASK)

#define TRACE_DBG_DETAIL_LEVEL(L)           ((L & TRACE_LEVEL_DBG_DETAIL_MASK) >> 24)


#define TL_URGENT           0x00000001
#define TL_ERROR            0x00000002
#define TL_ERR              0x00000002
#define TL_WARNING          0x00000004
#define TL_WARN             0x00000004
#define TL_INFO             0x00000008
#define TL_DEBUG            0x00000010
#define TL_DEBUG_DETAIL     0x00000020
#define TL_TRACE            0x00000040

#define MAKE_TL_DEBUG_DETAIL(L) (((L & 0x000000FF) << 24) | TL_DEBUG_DETAIL)

// used by trace writer.
SSTRACE_API void trace_va(unsigned int level, const char *fmt, ...);
SSTRACE_API void trace_vw(unsigned int level, const wchar_t *fmt, ...);
SSTRACE_API void trace_a(unsigned int level, const char *info);
SSTRACE_API void trace_w(unsigned int level, const wchar_t *info);

// used by the trace receiver.
// it's always the top most module, such as execute process
// the trace receiver need to set the callback to get the trace
typedef void (*PFNTraceCBA)(unsigned int level, const char *info);
typedef void (*PFNTraceCBW)(unsigned int level, const wchar_t *info);

SSTRACE_API PFNTraceCBA trace_receiver_set_cb_a(PFNTraceCBA cb);
SSTRACE_API PFNTraceCBW trace_receiver_set_cb_w(PFNTraceCBW cb);

SSTRACE_API unsigned int trace_receiver_set_levels(unsigned int levels);
SSTRACE_API unsigned int trace_receiver_get_levels();

SSTRACE_API void trace_receiver_detail_debug_levels_clear();
SSTRACE_API bool trace_receiver_detail_debug_levels_append(unsigned int detail_debug_level);
SSTRACE_API bool trace_receiver_detail_debug_levels_remove(unsigned int detail_debug_level);

// used by the trace receiver.
// customize the trace info format
typedef int (*PFNTraceFormatCBA)(char *info, size_t info_size, unsigned int level,
	const char *fmt, va_list vl);
typedef int (*PFNTraceFormatCBW)(wchar_t *info, size_t info_size, unsigned int level,
	const wchar_t *fmt, va_list vl);

SSTRACE_API PFNTraceFormatCBA trace_receiver_set_format_cb_a(PFNTraceFormatCBA cb);
SSTRACE_API PFNTraceFormatCBA trace_receiver_get_format_cb_a();
SSTRACE_API PFNTraceFormatCBW trace_receiver_set_format_cb_w(PFNTraceFormatCBW cb);
SSTRACE_API PFNTraceFormatCBW trace_receiver_get_format_cb_w();

//
SSTRACE_API bool get_trace_level_string_a(unsigned int level, char *level_string, size_t level_string_size);
SSTRACE_API bool get_trace_level_string_w(unsigned int level, wchar_t *level_string, size_t level_string_size);


#ifdef SS_TRACE_DISABLE
#define TraceV_A(l,f,...)
#define TraceV_W(l,f,...)
#define Trace_A(l,f)
#define Trace_W(l,f)
#define TraceReceiverSetCB_A(f)
#define TraceReceiverSetCB_W(f)
#define TraceReceiverSetFormatCB_A(f)
#define TraceReceiverSetFormatCB_W(f)

#define TraceReceiverSetLevels(l)
#define TraceReceiverGetLevels()
#define TraceReceiverDetailDebugLevelsClear()
#define TraceReceiverDetailDebugLevelsAppend(ddl)
#define trace_receiver_detail_debug_levels_remove(ddl)

#else // #ifdef SS_TRACE_DISABLE

#define TraceV_A trace_va
#define TraceV_W trace_vw
#define Trace_A trace_a
#define Trace_W trace_w
#define TraceReceiverSetCB_A trace_receiver_set_cb_a
#define TraceReceiverSetCB_W trace_receiver_set_cb_w
#define TraceReceiverSetFormatCB_A trace_receiver_set_format_cb_a
#define TraceReceiverSetFormatCB_W trace_receiver_set_format_cb_w

#define TraceReceiverSetLevels trace_receiver_set_levels
#define TraceReceiverGetLevels trace_receiver_get_levels
#define TraceReceiverDetailDebugLevelsClear trace_receiver_detail_debug_levels_clear
#define TraceReceiverDetailDebugLevelsAppend trace_receiver_detail_debug_levels_append
#define TraceReceiverDetailDebugLevelsRemove trace_receiver_detail_debug_levels_remove

#endif // #ifdef SS_TRACE_DISABLE

#ifdef _UNICODE
#define TraceV TraceV_W
#define Trace Trace_W
#define TraceReceiverSetCB TraceReceiverSetCB_W
#define TraceReceiverSetFormatCB TraceReceiverSetFormatCB_W
#else
#define TraceV TraceV_A
#define Trace Trace_A
#define TraceReceiverSetCB TraceReceiverSetCB_A
#define TraceReceiverSetFormatCB TraceReceiverSetFormatCB_A
#endif

#define TraceE_A(info) Trace_A(TL_ERR, info)
#define TraceW_A(info) Trace_A(TL_WARN, info)
#define TraceI_A(info) Trace_A(TL_INFO, info)
#define TraceD_A(info) Trace_A(TL_DEBUG, info)
#define TraceT_A(info) Trace_A(TL_TRACE, info)

#define TraceE_W(info) Trace_W(TL_ERR, info)
#define TraceW_W(info) Trace_W(TL_WARN, info)
#define TraceI_W(info) Trace_W(TL_INFO, info)
#define TraceD_W(info) Trace_W(TL_DEBUG, info)
#define TraceT_W(info) Trace_W(TL_TRACE, info)

#ifdef _UNICODE
#define TraceE(info) TraceE_W(info)
#define TraceW(info) TraceW_W(info)
#define TraceI(info) TraceI_W(info)
#define TraceD(info) TraceD_W(info)
#define TraceT(info) TraceT_W(info)
#else
#define TraceE(info) TraceE_A(info)
#define TraceW(info) TraceW_A(info)
#define TraceI(info) TraceI_A(info)
#define TraceD(info) TraceD_A(info)
#define TraceT(info) TraceT_A(info)
#endif

#define TraceVE_W(info, ...) TraceV_W(TL_ERR, info, ##__VA_ARGS__)
#define TraceVW_W(info, ...) TraceV_W(TL_WARN, info, ##__VA_ARGS__)
#define TraceVI_W(info, ...) TraceV_W(TL_INFO, info, ##__VA_ARGS__)
#define TraceVD_W(info, ...) TraceV_W(TL_DEBUG, info, ##__VA_ARGS__)
#define TraceVT_W(info, ...) TraceV_W(TL_TRACE, info, ##__VA_ARGS__)

#define TraceVE_A(info, ...) TraceV_A(TL_ERR, info, ##__VA_ARGS__)
#define TraceVW_A(info, ...) TraceV_A(TL_WARN, info, ##__VA_ARGS__)
#define TraceVI_A(info, ...) TraceV_A(TL_INFO, info, ##__VA_ARGS__)
#define TraceVD_A(info, ...) TraceV_A(TL_DEBUG, info, ##__VA_ARGS__)
#define TraceVT_A(info, ...) TraceV_A(TL_TRACE, info, ##__VA_ARGS__)

#define TraceVE(info, ...) TraceV(TL_ERR, info, ##__VA_ARGS__)
#define TraceVW(info, ...) TraceV(TL_WARN, info, ##__VA_ARGS__)
#define TraceVI(info, ...) TraceV(TL_INFO, info, ##__VA_ARGS__)
#define TraceVD(info, ...) TraceV(TL_DEBUG, info, ##__VA_ARGS__)
#define TraceVT(info, ...) TraceV(TL_TRACE, info, ##__VA_ARGS__)

_SSBASEL_END
_SSL_END

#endif
